package com.example.accessibilityservice.process;

import android.accessibilityservice.AccessibilityService;
import android.accessibilityservice.GestureDescription;
import android.app.Notification;
import android.app.PendingIntent;
import android.graphics.Path;
import android.graphics.Rect;
import android.os.Build;
import android.os.Handler;
import android.os.Message;
import android.text.TextUtils;
import android.util.Log;
import android.view.GestureDetector;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityNodeInfo;

import com.example.accessibilityservice.AccessibilityServiceInterface;

import java.util.LinkedList;
import java.util.List;
import java.util.PriorityQueue;
import java.util.Queue;

import androidx.annotation.NonNull;
import androidx.annotation.RequiresApi;

public class WXAccessibilityProcess extends AccessibilityProcessBase{
    private static final String TAG = WXAccessibilityProcess.class.getSimpleName();

    private AccessibilityServiceInterface accessibilityServiceInterface;

    private static final boolean need_ignore_mine = false; //是否忽略自己的红包

    private static final int WINDOW_STATUS_WAIT_MESSAGE = 0x00;//等待消息
    private static final int WINDOW_STATUS_OPEN_CHAT = 0x01;//在会话窗口
    private static final int WINDOW_STATUS_DETECTION = 0x02;//检测红包
    private static final int WINDOW_STATUS_MORE = 0x03;//更多消息状态

    private volatile int curWindowStatus = WINDOW_STATUS_WAIT_MESSAGE;//窗口状态

    private static final int RED_PACKAGE_STATUS_WAIT = 0xF0;//
    private static final int RED_PACKAGE_STATUS_OPEN = 0xF1;//红包打开
    private static final int RED_PACKAGE_STATUS_DETAIL = 0xF2;//红包详情
    private static final int RED_PACKAGE_STATUS_TIMEOUT = 0xF3;//红包详情

    private volatile int curRedPackageStatus = RED_PACKAGE_STATUS_WAIT;//红包状态


    private static final String CLASS_NAME_Notification = "android.app.Notification";
    private static final String CLASS_NAME_DETAILUI = "com.tencent.mm.plugin.luckymoney.ui.LuckyMoneyDetailUI";
    private static final String CLASS_NAME_NOTHOOK = "com.tencent.mm.plugin.luckymoney.ui.LuckyMoneyNotHookReceiveUI";
    private static final String CLASS_NAME_LAUNCHUI = "com.tencent.mm.ui.LauncherUI";
    private static final String CLASS_NAME_LISTVIEW = "android.widget.ListView";

    //对话框中红包外框id
    private static final String ID_RED_PACKAGE_ROOT = "com.tencent.mm:id/b47";
    //会话列表id
    private static final String ID_CHAT_LIST_ROOT = "com.tencent.mm:id/gkp";
    //小红点
    private static final String ID_CHAT_LIST_UNREAD = "com.tencent.mm:id/kmv";
    //打开红包后  红包打开按钮
    private static final String ID_READ_PACKAGE_OPEN_1 = "com.tencent.mm:id/giq";
    //更多消息
    private static final String ID_MORE_MESSAGE = "com.tencent.mm:id/b5m";

    private Handler mHandler;
    private static int DELAY_TIME = 300;
    private static final int RECEIVE_TIME_OUT = 1000;//点完领取之后的超时时间
    private ReceiveRedPackageTimeOutRun receiveRedPackageTimeOutRun;

    private static final int HANDLER_NEW_RED_PACKAGE = 0xf0;//来新包了
    private static final int HANDLER_OPEN_RED_PACKAGE = 0xf1;//打开
    private static final int HANDLER_OPEN_ALL = 0xf2;//全部打开
    private static final int HANDLER_PREFORM_BACK = 0xf3;//返回上一级\
    private static final int HANDLER_WAIT_RED_PACKAGE = 0xf4;//等待开字转完

    private volatile boolean isMoveSuccess = false;
    /**
     * 检测到的红包列表，其实没法根据列表一个个打开
     * 打开一个红包之后返回来调用这个就的info 会出现失败
     * 这个时候就是根据这个失败继续走下去吧  在检测一个当前页面
     * */
    private Queue<AccessibilityNodeInfo> mCurChatRedPackageLists;

    public WXAccessibilityProcess(AccessibilityServiceInterface serviceInterface){
        accessibilityServiceInterface = serviceInterface;
        if(null == mHandler){
            mHandler = new WXRedPGHandler();
        }
        if(null == mCurChatRedPackageLists){
            mCurChatRedPackageLists = new LinkedList<>();
        }
        if(null == receiveRedPackageTimeOutRun){
            receiveRedPackageTimeOutRun = new ReceiveRedPackageTimeOutRun();
        }
    }

    private class WXRedPGHandler extends Handler {
        @Override
        public void handleMessage(@NonNull Message msg) {
            if(null == msg)
                return;
            switch (msg.what){
                /**从列表中检出下一个红包*/
                case HANDLER_NEW_RED_PACKAGE:{
                    Log.d(TAG, "HANDLER_NEW_RED_PACKAGE.....");
                    if(!mCurChatRedPackageLists.isEmpty()){
                        AccessibilityNodeInfo redPGInfo = mCurChatRedPackageLists.poll();
                        Message message = mHandler.obtainMessage();
                        message.what = HANDLER_OPEN_RED_PACKAGE;
                        message.obj = redPGInfo;

                        mHandler.sendMessage(message);
                    } else {
                        mHandler.sendEmptyMessageDelayed(HANDLER_OPEN_ALL,DELAY_TIME);
                    }
                    break;
                }
                /**打开检出的红包*/
                case HANDLER_OPEN_RED_PACKAGE:{
                    Log.d(TAG, "HANDLER_OPEN_RED_PACKAGE.....");
                    openRedPackage((AccessibilityNodeInfo) msg.obj);
                    break;
                }
                /**所有检测到的红包都打开了，清除状态  返回等待*/
                case HANDLER_OPEN_ALL:{
                    Log.d(TAG, "HANDLER_OPEN_ALL.....");
                    mCurChatRedPackageLists.clear();
                    curWindowStatus = WINDOW_STATUS_WAIT_MESSAGE;
                    curRedPackageStatus = RED_PACKAGE_STATUS_WAIT;
                    mHandler.sendEmptyMessageDelayed(HANDLER_PREFORM_BACK,DELAY_TIME);
                    break;
                }
                /**回退一级*/
                case HANDLER_PREFORM_BACK:{
                    Log.d(TAG, "HANDLER_PREFOEM_BACK.....");
                    if(null != accessibilityServiceInterface)
                        accessibilityServiceInterface.performBackBtn();
                    break;
                }
                /**红包点开后会有一个加载的过程  期间需要等待*/
                case HANDLER_WAIT_RED_PACKAGE:{
                    Log.d(TAG, "HANDLER_WAIT_RED_PACKAGE.....");
                    if(null != accessibilityServiceInterface)
                        receiveRedPackage(accessibilityServiceInterface.getRoot());
                    break;
                }
            }
        }
    }

    @Override
    public void processEvent(AccessibilityEvent event, AccessibilityNodeInfo root) {
        int type = event.getEventType();
        Log.d(TAG,"processWXMessage type: " + type);
        Log.d(TAG,"processWXMessage className: " + event.getClassName());
        switch (type){
            case AccessibilityEvent.TYPE_VIEW_SCROLLED:{
                ////空闲 在会话列表则检测红点  或者  在会话中则清除状态
                if(WINDOW_STATUS_WAIT_MESSAGE == curWindowStatus){
                    String className = event.getClassName().toString();
                    if(!TextUtils.isEmpty(className)){
                        if(CLASS_NAME_LISTVIEW.equals(className.trim())){
                            if(checkIsChatList(root)){
                                checkUnreadCount(root);
                            } else {
                                mHandler.sendEmptyMessageDelayed(HANDLER_OPEN_ALL,DELAY_TIME);
                            }
                        }
                    }
                } else if(WINDOW_STATUS_OPEN_CHAT == curWindowStatus){
                    //检测红包
                    Log.d(TAG,"聊天打开,检测红包");
                    detectionRedPackage(root);
                } else if(WINDOW_STATUS_MORE == curWindowStatus && !isMoveSuccess){
                    isMoveSuccess = true;
                    detectionRedPackage(root);
                }
                break;
            }
            case AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED:{
                //收到通知 空闲 则跳转到 对话框
                if(WINDOW_STATUS_WAIT_MESSAGE == curWindowStatus){
                    String className = event.getClassName().toString();
                    String text = event.getText().toString();
                    Log.d(TAG,"processWXMessage text: " + text);
                    if(!TextUtils.isEmpty(className) && CLASS_NAME_Notification.equals(className)){
                        Notification notification = (Notification) event.getParcelableData();
                        if(null != notification){
                            try {
                                Log.d(TAG,"通过通知打开微信");
                                notification.contentIntent.send();
                                curWindowStatus = WINDOW_STATUS_OPEN_CHAT;
                            } catch (PendingIntent.CanceledException e) {
                                e.printStackTrace();
                            }
                        }
                    }
                }
                break;
            }
            case AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED:{
                ///非空闲状态(在会话中/检测红包中)，处理窗口状态变化事件
                if(WINDOW_STATUS_OPEN_CHAT == curWindowStatus){
                    //检测红包
                    Log.d(TAG,"聊天打开,检测是否存在更多消息");
                    detectionRedPackage(root);
                } else if(WINDOW_STATUS_DETECTION == curWindowStatus){
                    //正在打开红包
                    if(RED_PACKAGE_STATUS_OPEN == curRedPackageStatus){
                        String className = event.getClassName().toString();
                        if(!TextUtils.isEmpty(className)){
                            //根据不同的classname 执行不同操作
                            if(CLASS_NAME_NOTHOOK.equals(className.trim())){
                                //领取红包
                                receiveRedPackage(root);
                                //添加超时操作  默认1秒
                                mHandler.postDelayed(receiveRedPackageTimeOutRun,RECEIVE_TIME_OUT);
                            } else if(CLASS_NAME_DETAILUI.equals(className.trim())){
                                //红包详情页  则返回上一级  打开下一个红包
                                mHandler.sendEmptyMessageDelayed(HANDLER_PREFORM_BACK,DELAY_TIME);
                                mHandler.sendEmptyMessageDelayed(HANDLER_NEW_RED_PACKAGE,DELAY_TIME);
                            } else if(CLASS_NAME_LAUNCHUI.equals(className.trim())){
                                //走到这里一般是红包打开失败了  重新检测一次
                                Log.d(TAG,"领取了一个红包,继续检测红包");
                                detectionRedPackage(root);
                            }
                        }
                    }
                }
                break;
            }
        }
    }

    @Override
    public String getPackageName() {
        return "com.tencent.mm";
    }

    /**
     * 是否已经领取
     * @param info
     * @return
     */
    private boolean checkUnclaimed(AccessibilityNodeInfo info){
        AccessibilityNodeInfo parent = info.getParent();
        if(null != parent){
            List<AccessibilityNodeInfo> list = parent.findAccessibilityNodeInfosByText("已领取");
            if(list != null && !list.isEmpty()){
                return false;
            }
        }
        return true;
    }

    /**
     * 检测是否是自己发的红包  可以通过need_ignore_mine控制是否打开自己发的红包
     * @param info 红包
     * @param root 根
     * @return
     */
    private boolean checkIsMine(AccessibilityNodeInfo info, AccessibilityNodeInfo root){
        if(!need_ignore_mine){
            return false;
        }
        Rect rootRect = new Rect();
        root.getBoundsInScreen(rootRect);

        Rect rect = new Rect();
        info.getBoundsInScreen(rect);
        if((rect.right+rect.left)/2 > (rootRect.right+rootRect.left)/2){
            return true;
        }
        return false;
    }

    /**
     * 检测当前是否在会话列表
     * @param info
     * @return
     */
    private boolean checkIsChatList(AccessibilityNodeInfo info){
        List<AccessibilityNodeInfo> list = info.findAccessibilityNodeInfosByViewId(ID_CHAT_LIST_ROOT);
        if(list != null && !list.isEmpty()){
            return true;
        }
        return false;
    }

    /**
     * 检测未读小红点
     * @param root
     */
    private void checkUnreadCount(AccessibilityNodeInfo root){
        List<AccessibilityNodeInfo> list = root.findAccessibilityNodeInfosByViewId(ID_CHAT_LIST_UNREAD);
        if(list == null || list.isEmpty()){
            Log.w(TAG, "未检测到有未读消息。");
            return;
        }
        for(AccessibilityNodeInfo info:list){
            if(!TextUtils.isEmpty(info.getText().toString()) && null != info.getParent()){
                if(info.getParent().performAction(AccessibilityNodeInfo.ACTION_CLICK)){
                    curWindowStatus = WINDOW_STATUS_OPEN_CHAT;
                    Log.w(TAG, "进去会话成功。");
                } else {
                    Log.w(TAG, "进入会话失败。");
                }
            }
        }
    }


    @Deprecated
    private void detectMoreMessage(AccessibilityNodeInfo root){

        Log.d(TAG,"检测是否更多消息");
        if(null == root){
            mHandler.sendEmptyMessageDelayed(HANDLER_OPEN_ALL,DELAY_TIME);
            return;
        }
        //查找看没有有更多消息
        List<AccessibilityNodeInfo> moreMessageList = root.findAccessibilityNodeInfosByViewId(ID_MORE_MESSAGE);
        if(null == moreMessageList || moreMessageList.isEmpty()){
            //检测红包中

            detectionRedPackage(root);
        } else {
            curWindowStatus = WINDOW_STATUS_MORE;
            moreMessageList.get(0).getParent().performAction(AccessibilityNodeInfo.ACTION_CLICK);
            //向下移动屏幕
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                moveScroll(root);
            }
        }
    }

    @RequiresApi(api = Build.VERSION_CODES.N)
    private void moveScroll(AccessibilityNodeInfo root){
        Path path = new Path();
        path.moveTo(540,1500);
        path.lineTo(540,300);
        if(null != accessibilityServiceInterface)
            isMoveSuccess = false;
            accessibilityServiceInterface.performMove(path, new AccessibilityService.GestureResultCallback() {
                @Override
                public void onCompleted(GestureDescription gestureDescription) {
                    Log.d(TAG,"滑动屏幕成功");
                }

                @Override
                public void onCancelled(GestureDescription gestureDescription) {
                    super.onCancelled(gestureDescription);
                    Log.d(TAG,"滑动屏幕失败");
                }
            });
    }
    /**
     * 检测包
     * @param root
     */
    private void detectionRedPackage(AccessibilityNodeInfo root){
        Log.d(TAG,"检测红包");
        if(null == root){
            mHandler.sendEmptyMessageDelayed(HANDLER_OPEN_ALL,DELAY_TIME);
            return;
        }
        //查找红包
        List<AccessibilityNodeInfo> redPackageList = root.findAccessibilityNodeInfosByViewId(ID_RED_PACKAGE_ROOT);
        if(null == redPackageList || redPackageList.isEmpty()){
            if(isMoveSuccess){
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                    moveScroll(root);
                }
            } else {
                Log.d(TAG,"没有检测到红包");
                mHandler.sendEmptyMessageDelayed(HANDLER_OPEN_ALL,DELAY_TIME);
            }

            return;
        }
        mCurChatRedPackageLists.clear();
        curWindowStatus = WINDOW_STATUS_DETECTION;
        for(AccessibilityNodeInfo redPackageInfo:redPackageList){
            if(checkUnclaimed(redPackageInfo) && !checkIsMine(redPackageInfo,root))
                mCurChatRedPackageLists.add(redPackageInfo);
        }
        mHandler.sendEmptyMessageDelayed(HANDLER_NEW_RED_PACKAGE,DELAY_TIME);
    }

    /**
     * 点开包
     * @param redPGInfo 包信息
     */
    private void openRedPackage(AccessibilityNodeInfo redPGInfo){
        if(null == redPGInfo){
            mHandler.sendEmptyMessageDelayed(HANDLER_NEW_RED_PACKAGE,DELAY_TIME);
            return;
        }
        Log.d(TAG,"打开红包...");
        if(redPGInfo.isClickable()){
            curRedPackageStatus = RED_PACKAGE_STATUS_OPEN;
            if(redPGInfo.performAction(AccessibilityNodeInfo.ACTION_CLICK)){
                Log.d(TAG,"打开红包成功...");
            } else {
                Log.d(TAG,"打开红包失败.");
            }
        }
    }

    /**
     * 领取红包超时
     */
    private class ReceiveRedPackageTimeOutRun implements Runnable{

        @Override
        public void run() {
            Log.w(TAG, "ReceiveRedPackageTimeOutRun is run.....");
            curRedPackageStatus = RED_PACKAGE_STATUS_TIMEOUT;
        }
    }

    /**
     * 领取红包
     * @param root
     */
    private void receiveRedPackage(AccessibilityNodeInfo root){
        //超时了
        if(curRedPackageStatus == RED_PACKAGE_STATUS_TIMEOUT){
            Log.w(TAG, "领取超时，领取下一个...");
            mHandler.sendEmptyMessageDelayed(HANDLER_PREFORM_BACK,DELAY_TIME);
            mHandler.sendEmptyMessageDelayed(HANDLER_NEW_RED_PACKAGE,DELAY_TIME);
            return;
        }
        Log.w(TAG, "领取红包...");
        if(root == null) {
            Log.w(TAG, "rootWindow为空");
            mHandler.sendEmptyMessageDelayed(HANDLER_NEW_RED_PACKAGE,DELAY_TIME);
            return;
        }

        List<AccessibilityNodeInfo> openList = root.findAccessibilityNodeInfosByViewId(ID_READ_PACKAGE_OPEN_1);
        if(null == openList || openList.isEmpty()){
            Log.w(TAG, "正在加载.");
            mHandler.sendEmptyMessageDelayed(HANDLER_WAIT_RED_PACKAGE,100);
            return;
        }
        mHandler.removeCallbacks(receiveRedPackageTimeOutRun);
        curRedPackageStatus = RED_PACKAGE_STATUS_OPEN;
        for(AccessibilityNodeInfo open:openList){
            if(open.isClickable()){
                if(open.performAction(AccessibilityNodeInfo.ACTION_CLICK)){
                    Log.w(TAG, "领取成功。");
                } else {
                    Log.w(TAG, "领取失败。");
                }
                return;
            }
        }
    }
}
